<template>
  <!-- 这个组件是一个代码片段(根元素大于1), 不是一个根元素 -->
  <div class="address">
    <div class="text">
      <div v-if="!showAddress" class="none">您需要先添加收货地址才可提交订单.</div>
      <div v-if="showAddress">
        <p><span>收<i/>货<i/>人：</span>{{ showAddress.receiver }}</p>
        <p><span>联系方式：</span>{{ filterContact(showAddress.contact) }}</p>
        <p><span>收货地址：</span>{{ showAddress.fullLocation.replace(/ /g, '') }}{{ showAddress.address }}</p>
      </div>
    </div>
    <a v-if="showAddress"
       class="change-add"
       href="javascript:;"
       @click="openAddEditDialog(showAddress)">修改地址</a>
    <div class="action">
      <XtxButton size="small" @click="openSwitchDialog">切换地址</XtxButton>
      <XtxButton size="small" @click="openAddEditDialog()">添加地址</XtxButton>
    </div>
  </div>
  <!-- 对话框组件, 并没有使用函数方式调用组件, 所以组件的地方预留一个位置, 用一个变量控制组件显示和隐藏 -->
  <XtxDialog v-model:visible="visibleSwitchDialog" title="切换收货地址">
    <template #body>
      <div v-for="item in list"
           :key="item.id"
           :class="{active: selectedAddress && selectedAddress.id === item.id}"
           class="text item"
           @click="selectedAddress = item">
        <ul>
          <li><span>收<i/>货<i/>人：</span>{{ item.receiver }}</li>
          <li><span>联系方式：</span>{{ filterContact(item.contact) }}</li>
          <!-- todo: replace(/ /g, '')  这个操作是为了干什么, 把空格替换为空字符串 -->
          <li><span>收货地址：</span>{{ item.fullLocation.replace(/ /g, '') + item.address }}</li>
        </ul>
      </div>
    </template>
    <template v-slot:footer>
      <XtxButton style="margin-right: 20px" type="gray" @click="visibleSwitchDialog = false">取消</XtxButton>
      <XtxButton type="primary" @click="confirmAddressFn">确认</XtxButton>
    </template>
  </XtxDialog>

  <!-- 收货地址添加编辑组件 -->
  <AddressAdd ref="addRef" @on-success="addSuccessHandler"></AddressAdd>
  <AddressEdit ref="editRef" @on-success="editSuccessHandler"></AddressEdit>
</template>

<script>
import { ref } from 'vue'
import AddressAdd from '@/components/member/AddressAdd'
import AddressEdit from '@/components/member/AddressEdit'
import Message from '@/components/library/Message'

export default {
  name: 'CheckAddress',
  components: {
    AddressEdit,
    AddressAdd
  },
  props: {
    list: {
      type: Array,
      default: () => []
    }
  },
  // 1.在拥有根元素的组件中(根元素只有一个), 触发自定义事件使用, 有没有emits选项无所谓
  // 2.如果你的组件渲染的是代码片段, vue3.0规范, 需要在emits中声明你所触发的自定义事件
  // 3.提倡: 组件触发的自定义事件, 需要在emits选项声明下 (代码可读性提高)
  emits: ['change'],
  setup(props, { emit }) {
    // 1.找到默认收货地址
    // 2.没有默认收货地址, 使用第一条收货地址
    // 3.如果没有数据, 提示添加

    // 收货地址组件显示的地址
    const showAddress = ref(null)
    // AddressAdd组件的ref对象
    const addRef = ref(null)
    // AddressEdit组件的ref对象
    const editRef = ref(null)

    // todo 这里的逻辑还是要思考下, 不妥当
    const defaultAddress = props.list.find(item => item.isDefault === 0)
    if (defaultAddress) {
      showAddress.value = defaultAddress
    } else if (props.list.length > 0) {
      // 加上一个注释: 忽略下面代码检测eslint |
      // 解释 不能把一个props对象数据赋值给响应式数据, 因为对象方式是引用的, 改了响应式数据, props数据也会改变
      // eslint-disable-next-line vue/no-setup-props-destructure
      showAddress.value = props.list[0]
    } else {
      showAddress.value = null
    }

    /**
     * 过滤手机号
     * @param contact 手机号, 注意由于表单设置了 text="number", 所以这个参数是数值类型
     */
    const filterContact = (contact) => {
      // 使用正则替换
      return (contact + '').replace(/^(\d{3})\d{4}(\d{4})$/, '$1****$2')
      // return contact.substr(0, 3) + '****' + contact.substr(7)
    }

    // 控制切换地址弹出层显示和隐藏
    const visibleSwitchDialog = ref(false)

    // 收货地址组件初始化的时候需要得到一个默认的地址Id通知给check结算组件
    // showAddress.value && showAddress.value.id 等于下面那个三元表达式
    emit('change', showAddress.value ? showAddress.value.id : null)
    // ES6的语法 showAddress.value不为null, 才取值
    // showAddress.value?.id  === showAddress.value && showAddress.value.id
    // emit('change', showAddress.value?.id)

    // 记录当前选中的address信息(里面地址Id, 要发送给父组件check结算组件)
    const selectedAddress = ref(null)

    // 点击切换地址对话框的确认, 修改切换地址操作
    const confirmAddressFn = () => {
      // 显示的地址换成选中的地址
      showAddress.value = selectedAddress.value
      // 把选中地址ID通知check结算组件
      emit('change', showAddress.value.id)
      // 数据使用完毕后, 清空地址选中状态, 变成w未选中状态
      selectedAddress.value = null
      // 关闭对话框
      visibleSwitchDialog.value = false

      // 加一个提示框
      Message({
        type: 'success',
        text: '切换地址成功'
      })
    }

    // 打开切换地址对话框
    const openSwitchDialog = () => {
      // 将之前的选中地址改为null, (清空上次的勾选状态)
      selectedAddress.value = null
      // 打开对话框
      visibleSwitchDialog.value = true
    }

    /**
     * 打开添加 | 修改地址对话框
     * @param address 等同于 showAddress.value 对象, 从模板传递的参数都是 ref.value 数据
     */
    const openAddEditDialog = (address) => {
      // bug点
      // 添加 @click="openAddEditDialog" 使用方法名称, 点击添加按钮, address默认是一个PointerEvent事件对象
      //    而参数address不是undefined, 要想得到undefined
      //    应该用方法调用方式, 且不传值 @click="openAddEditDialog()"
      // 修改 地址对象
      // RefImpl {dep: 'xx', _shallow: false, value: Proxy {id: '123343453', receiver: '大笨蛋', ...} }
      // console.log('showAddress', showAddress)
      // Proxy {id: '123343453', receiver: '大笨蛋', ...}
      // console.log('showAddress.value', showAddress.value)
      // console.log('address', address)                 // Proxy {id: '123343453', receiver: '大笨蛋', ...}
      // console.log('address.value', address.value)     // undefined
      if (address) {
        editRef.value.open(address)
      } else {
        addRef.value.open()
      }
    }

    /**
     * AddressAdd组件添加地址成功后, 接收其自定义事件函数
     * @param formData
     */
    const addSuccessHandler = (formData) => {
      // 如果是添加: 让list中追加一条
      // 当你在修改formData的时候, 数组中的数据也会更新, 因为是用一个引用地址
      // 啥时候修改fromData, 当你打开对话框需要清空之前的输入信息
      // 所以需要使用深拷贝clone克隆fromData数据
      const jsonStr = JSON.stringify(formData)

      // props自定义属性, 对象数组传递的是引用, 所以说在组件中修改props的对象字段或数组元素
      // 这种做法是行的通的, 但是Eslint发出了警告而已, 不建议我们这样做
      // eslint-disable-next-line vue/no-mutating-props
      props.list.unshift(JSON.parse(jsonStr))
    }

    /**
     * AddressEdit组件添加地址成功后, 接收其自定义事件函数
     * @param formData
     */
    const editSuccessHandler = (formData) => {
      // bug点, 这里的 === 等于判断号, 写成了赋值 =
      const editAddress = props.list.find(item => item.id === formData.id)
      for (let key in editAddress) {
        editAddress[key] = formData[key]
      }
    }

    return {
      showAddress,
      filterContact,
      visibleSwitchDialog,
      selectedAddress,
      confirmAddressFn,
      openSwitchDialog,
      addRef,
      editRef,
      openAddEditDialog,
      addSuccessHandler,
      editSuccessHandler
    }
  }
}
</script>

<style lang="less" scoped>

.xtx-dialog {
  .text {
    display: flex;
    align-items: center;
    min-height: 90px;

    &.item {
      border: 1px solid #f5f5f5;
      margin-bottom: 10px;
      cursor: pointer;

      &.active, &:hover {
        border-color: @xtxColor;
        background: lighten(@xtxColor, 50%);
      }

      > ul {
        padding: 10px;
        font-size: 14px;
        line-height: 30px;

        li {
          span {
            color: #999;
            margin-right: 5px;

            > i {
              width: 0.5em;
              display: inline-block;
            }
          }
        }
      }
    }
  }
}

.address {
  display: flex;
  align-items: center;
  height: 130px;
  padding: 20px 0;

  border: 1px solid #f5f5f5;
  border-radius: 3px;

  .text {
    flex: 1;
    width: 618px;
    padding-left: 20px;

    .none {
      padding-left: 200px;
      color: #999;
    }

    p {
      height: 30px;
      line-height: 30px;

      span {
        margin-right: 5px;
        color: #999;

        > i {
          display: inline-block;
          width: 0.5em;
        }
      }
    }
  }

  .change-add {
    width: 160px;
    text-align: center;
    color: @xtxColor;
  }

  .action {
    //flex: 1;
    display: flex;
    width: 420px;
    justify-content: center;
    align-items: center;
    height: 100%;

    border-left: 1px solid #f5f5f5;

    ::v-deep .xtx-button {
      width: 140px;
      height: 46px;

      &:first-child {
        margin-right: 10px;
      }
    }
  }
}
</style>
